package com.kt.thread.demo;

import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by tangwy on 2016/1/16.
 */

/**
 * 读写锁，支持并发读取数据，互斥同时写数据，当程序正在写数据时，其他的读锁也应该等待。
 */
public class ReadWriteLockTest {
    private static final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private Object data = null;

    /**
     * 读取数据
     *
     * @return
     */
    public Object readData() throws Exception {
        //加锁
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "开始读取数据.......");
            Thread.sleep((long) (Math.random() * 1000));
            System.out.println("data=" + data);
            System.out.println(Thread.currentThread().getName() + "数据读取完成");
            return data;
        } finally {
            //解锁
            readWriteLock.readLock().unlock();
        }
    }

    /**
     * 写入数据
     */
    public void writeData() {
        //加锁
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "开始写入数据.......");
            Thread.sleep((long) (Math.random() * 1000));
            data = new Random().nextInt(100);
            System.out.println("data=" + data + "," + Thread.currentThread().getName() + "数据写入完成...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //解锁
            readWriteLock.writeLock().unlock();
        }
    }

    /**
     * 同时读取和写入数据
     *
     * @return
     */
    public Object readAndWrite() {
        //加上读锁
        readWriteLock.readLock().lock();
        try {
            if (data == null) {
                //如果没有数据解除读锁，开始写入数据
                readWriteLock.readLock().unlock();
                readWriteLock.writeLock().lock();
                /**
                 *  防止第二个写线程再将data赋值一次,所以再判断一次data==null,假如有两个写线程到了上面那句代码，
                 *  其中一个线程获得锁，然后开始为data赋值，当这个线程解锁后，另一个
                 *  线程就会获得锁的然后开始写数据，所以要判断下是否为null，为Null则赋值
                 *  不为null就说明已经赋值了
                 */
                try {
                    if (data == null) {
                        data = new Random().nextInt(1000);
                    }
                } finally {
                    readWriteLock.writeLock().unlock();
                }
                readWriteLock.readLock().lock();
            }
            return data;
        } finally {
            readWriteLock.readLock().unlock();
        }
    }


    /*public  Object test(){
        try{
            readWriteLock.readLock().lock();
            if(data==null){
                readWriteLock.readLock().unlock();
                try {
                    readWriteLock.writeLock().lock();
                    if(data==null){
                        data="data";
                    }
                }finally {
                    readWriteLock.writeLock().unlock();
                }
               readWriteLock.readLock().lock();
            }
            return data;
        }finally {
            readWriteLock.readLock().unlock();
        }
    }*/
}
